from __future__ import division

from locals import *

class Object(object):
	graphic = "object.png"
	
	hostile = False
	
	_passable = False
	_push = True
	
	_immunities = ()
	_damage = ()
	
	walk_speed = 6
	
	_removed = False
	
	def __init__(self, map, position):
		super(Object, self).__init__(map, position)
		
		self.map = map
		
		self.items = []
		
		self.position = position
		self.last_position = position
		
		self.speed = 0
		self.distance = 0
		self.direction = 0
		self.moving = False
		self.frozen = (False, False)
	
	def remove(self):
		if not self._removed:
			self.map.deindex(self)
			self._removed = True
	
	def save(self, variables):
		for key, value in variables["objects"].iteritems():
			if value == self.__class__:
				name = key
		
		return "%s: %s" % (name, str(self.position))
	
	def update(self):
		if not self._removed:
			if (self.moving and not self.distance < self.speed) or not self.moving:
				self.map.stand(self.last_position, self)
		
		if self.moving:		
			if 0 < self.distance:
				self.distance -= 1
			else:
				self.last_position = self.position
				self.distance = 0
				self.speed = 0
				self.moving = False
				self.map.step(self.position, self)	
			
	def _draw_position(self):
		x, y = self.position
		old_x, old_y = self.last_position
		
		if self.moving:
			ratio = 1 - (self.distance / self.speed)
			
			if x != old_x:
				x = old_x + (x - old_x) * ratio
					
			if y != old_y:
				y = old_y + (y - old_y) * ratio
		

		return (x * 32, y * 32)
	
	def draw(self, surface):				
		surface.blit(self.graphic, self._draw_position())
		
	def passable(self, object):
		return self._passable
	
	def teleport(self, position):
		self.last_position = self.position
		self.position = position
		
		self.map.move(self)
		
		self.last_position = position
	
	def move(self, movement, speed):
		move_x, move_y = movement
		
		self.direction = directions[movement]
		
		x, y = self.position
		
		new_position = (x + move_x, y + move_y)
		
		if self.map.passable(new_position, self):
			if not self.moving:
				self.speed = 0
				self.speed = speed
				self.distance = speed
			
			self.distance = speed
			self.speed = speed
			
			self.moving = True
			
			old_x, old_y = self.last_position
			
			diff_x, diff_y = x - old_x, y - old_y
			
			self.last_position = self.position
			
			self.position = new_position
			self.map.move(self)
			
			self.last_position = (x - diff_x, y - diff_y)
			
			return True
			
		elif self._push:
			if self.map.push(new_position, self, movement, speed):
				return self.move(movement, speed)
			else:
				return False

	def give(self, item):
		return False

	def push(self, pusher, movement, speed):
		return self.passable(pusher)
		
	def step(self, stepper):
		if self._damage:
			stepper.kill(self, self._damage)
		
	def stand(self, stander):
		pass

	def kill(self, killer, damage_types):
		return False

class Tile(Object):
	graphic = "tile.png"
	_symbols = " "
	
	_push = False
	
	_passable = True
	_match_edges = True
	
	def _subtiles(self, configuration):
		"""This is a painful 'algorithm' for finding the right subtiles to use
		to match similar tile edges.
		"""
		tl = 0
		tr = 1
		bl = 2
		br = 3
		
		if self._match_edges:
			if configuration[0 + 1][-1 + 1]:			
				if configuration[-1 + 1][0 + 1]:			
					if configuration[-1 + 1][-1 + 1]:
						tl += 12
					else:
						tl += 8
				else:
					tl += 6
			elif configuration[-1 + 1][0 + 1]:
				tl += 4
						
			if configuration[-1 + 1][0 + 1]:
				if configuration[0 + 1][1 + 1]:
					if configuration[-1 + 1][1 + 1]:
						tr += 12
					else:
						tr += 8
				else:
					tr += 4
			elif configuration[0 + 1][1 + 1]:
				tr += 5
						
			if configuration[0 + 1][1 + 1]:	
				if configuration[1 + 1][0 + 1]:
					if configuration[1 + 1][1 + 1]:
						br += 12
					else:
						br += 8
				else:
					br += 4
			elif configuration[1 + 1][0 + 1]:
				br += 2
						
			if configuration[1 + 1][0 + 1]:
				if configuration[0 + 1][-1 + 1]:
					if configuration[1 + 1][-1 + 1]:
						bl += 12
					else:
						bl += 8
				else:
					bl += 2
			elif configuration[0 + 1][-1 + 1]:
				bl += 5
				
		return ((tl, tr), (bl, br))

	def _transform(self, tile):
		x, y = self.position
		
		self.map[y][x] = tile(self.map, self.position)
		self.map._render_tiles(self.map.tile_render, (x - 1, y - 1, 3, 3))

	def __getitem__(self, index):
		if self._match_edges:
			size = 16
		else:
			size = 32
		
		return self.graphic.subsurface((index * size, 0, 16, 16))

	def symbol(self):
		return self._symbols[self.direction]

	def update(*args):
		pass

	def _draw_position(self):
		x, y = self.position
		
		return (x * 32, y * 32)

	def draw(self, surface, configuration=((0,0,0),(0,0,0),(0,0,0))):
		position = self._draw_position()
		
		if self._match_edges:
			for y, row in enumerate(self._subtiles(configuration)):
				for x, subtile in enumerate(row):
					surface.blit(self[subtile], (position[0] + (x * 16), position[1] + (y * 16)))
		else:
			surface.blit(self.graphic, position)
	
	def teleport(*args):
		return False
		
	def move(*args):
		return False
		
	def step(*args):
		pass

class StaticObject(Object):
	_passable = True
	_push = False
	
	def move(*args):
		return False

class Item(Object):
	graphic = "item.png"
	
	_passable = True
	_push = False
	
	def _take(self, taker):
		if taker.give(self):
			self.remove()
	
	def step(self, stepper):
		self._take(stepper)
		
	def stand(self, stander):
		self._take(stander)

class Character(Object):
	graphic = "character.png"
	
	_passable = True
	_push = True
	direction = 1
	
	_frame_delay = 4
	
	dead = False

	def __init__(self, map, position, direction):
		super(Character, self).__init__(map, position)
		
		self.direction = direction
		self._frame = 0

	def save(self, variables):
		for key, value in variables["directions"].iteritems():
			if value == self.direction:
				direction = key
		
		return "%s, %s" % (super(Character, self).save(variables), direction)

	def update(self):
		super(Character, self).update()
		
		if self.moving and not any(self.frozen):
			self._frame += 1
			
			if self._frame >= self._frames * self._frame_delay:
				self._frame = 0

	def draw(self, surface):
		frame = self._frame // self._frame_delay
		
		surface.blit(self.graphic.subsurface(self.direction * 32, frame * 32, 32, 32), self._draw_position())
	
	def give(self, item):
		self.items.append(item.name)

		return True

	def die(self):
		self.dead = True
		self.remove()
				